home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / wind.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  30.9 KB  |  1,272 lines

  1. /*
  2.  * wind 1.1.0 - a plug-in for the GIMP
  3.  *
  4.  * Copyright (C) Nigel Wetten
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  * Contact info: nigel@cs.nwu.edu
  21.  * Version: 1.0.0
  22.  *
  23.  * Version: 1.1.0
  24.  * May 2000 tim copperfield [timecop@japan.co.jp]
  25.  *
  26.  * Added dynamic preview.
  27.  *
  28.  */
  29.  
  30. #include "config.h"
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <gtk/gtk.h>
  37.  
  38. #include <libgimp/gimp.h>
  39. #include <libgimp/gimpui.h>
  40.  
  41. #include "libgimp/stdplugins-intl.h"
  42.  
  43.  
  44. #define PLUG_IN_NAME "wind"
  45.  
  46. #define COMPARE_WIDTH   3
  47.  
  48. #define SCALE_WIDTH   200
  49. #define MIN_THRESHOLD   0
  50. #define MAX_THRESHOLD  50
  51. #define MIN_STRENGTH    1
  52. #define MAX_STRENGTH   50
  53. #define PREVIEW_SIZE  128
  54.  
  55. typedef enum
  56. {
  57.   LEFT,
  58.   RIGHT
  59. } direction_t;
  60.  
  61. typedef enum
  62. {
  63.   RENDER_WIND,
  64.   RENDER_BLAST
  65. } algorithm_t;
  66.  
  67. typedef enum
  68. {
  69.   BOTH,
  70.   LEADING,
  71.   TRAILING
  72. } edge_t;
  73.  
  74.  
  75. static void query (void);
  76. static void run   (gchar   *name,
  77.            gint     nparams,
  78.            GimpParam  *param,
  79.            gint    *nreturn_vals,
  80.            GimpParam **return_vals);
  81.  
  82. static void dialog_box       (GimpDrawable   *drawable);
  83. static void ok_callback      (GtkWidget   *widget, 
  84.                   gpointer     data);
  85. static void radio_callback   (GtkWidget   *widget, 
  86.                   gpointer     data);
  87.  
  88. static gint render_effect    (GimpDrawable   *drawable, 
  89.                   gboolean     preview_mode);
  90. static void render_wind      (GimpDrawable   *drawable, 
  91.                   gint         threshold, 
  92.                   gint         strength,
  93.                   direction_t  direction, 
  94.                   edge_t       edge, 
  95.                   gboolean     preview_mode);
  96. static void render_blast     (GimpDrawable   *drawable, 
  97.                   gint         threshold, 
  98.                   gint         strength,
  99.                   direction_t  direction, 
  100.                   edge_t       edge, 
  101.                   gboolean     preview_mode);
  102. static gint render_blast_row (guchar      *buffer, 
  103.                   gint         bytes, 
  104.                   gint         lpi,
  105.                   gint         threshold,
  106.                   gint         strength, 
  107.                   edge_t       edge);
  108. static void render_wind_row  (guchar      *sb, 
  109.                   gint         bytes, 
  110.                   gint         lpi, 
  111.                   gint         threshold,
  112.                   gint         strength, 
  113.                   edge_t       edge);
  114.  
  115.  
  116. static void get_derivative     (guchar  *pixel_R1, 
  117.                 guchar  *pixel_R2,
  118.                 edge_t   edge, 
  119.                 gboolean has_alpha,
  120.                 gint    *derivative_R,
  121.                 gint    *derivative_G, 
  122.                 gint    *derivative_B,
  123.                 gint    *derivative_A);
  124. static gint threshold_exceeded (guchar  *pixel_R1, 
  125.                 guchar  *pixel_R2,
  126.                 edge_t   edge, 
  127.                 gint     threshold,
  128.                 gboolean has_alpha);
  129. static void reverse_buffer     (guchar  *buffer, 
  130.                 gint     length, 
  131.                 gint     bytes);
  132.  
  133. static void       fill_preview   (GtkWidget *preview_widget, 
  134.                   GimpDrawable *drawable);
  135. static GtkWidget *preview_widget (GimpDrawable *drawable);
  136.  
  137.  
  138. GimpPlugInInfo PLUG_IN_INFO =
  139. {
  140.   NULL,     /* init_proc  */
  141.   NULL,     /* quit_proc  */
  142.   query, /* query_proc */
  143.   run     /* run_proc   */
  144. };
  145.  
  146.  
  147. /*********************
  148.   Globals
  149.   *******************/
  150.  
  151. /* This is needed to communicate the result from the dialog
  152.    box button's callback function*/
  153. static gint dialog_result = -1;
  154.  
  155. struct config_tag
  156. {
  157.   gint        threshold;     /* derivative comparison for edge detection */
  158.   direction_t direction;     /* of wind, LEFT or RIGHT */
  159.   gint        strength;         /* how many pixels to bleed */
  160.   algorithm_t alg;           /* which algorithm */
  161.   edge_t      edge;          /* controls abs, ne+ static guchar *preview_bits;
  162. + static GtkWidget *preview;
  163. gation of derivative */
  164. };
  165.  
  166. typedef struct config_tag config_t;
  167. config_t config =
  168. {
  169.   10,          /* threshold for derivative edge detection */
  170.   LEFT,        /* bleed to the right */
  171.   10,          /* how many pixels to bleed */
  172.   RENDER_WIND, /* default algorithm */
  173.   LEADING      /* abs(derivative); */
  174. };
  175.  
  176. static guchar    *preview_cache;
  177. static GtkWidget *preview;
  178. static gint       preview_cache_rowstride;
  179. static gint       preview_cache_bpp;
  180.  
  181. MAIN ()
  182.  
  183. static void
  184. query (void)
  185. {
  186.   static GimpParamDef args[] =
  187.   {
  188.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  189.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  190.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  191.     { GIMP_PDB_INT32, "threshold", "Controls where blending will be done >= 0" },
  192.     { GIMP_PDB_INT32, "direction", "Left or Right: 0 or 1" },
  193.     { GIMP_PDB_INT32, "strength", "Controls the extent of the blending > 1" },
  194.     { GIMP_PDB_INT32, "alg", "WIND, BLAST" },
  195.     { GIMP_PDB_INT32, "edge", "LEADING, TRAILING, or BOTH" }
  196.   };
  197.   static gint nargs = sizeof (args) / sizeof (args[0]);
  198.  
  199.   gimp_install_procedure ("plug_in_wind",
  200.               "Renders a wind effect.",
  201.               "Renders a wind effect.",
  202.               "Nigel Wetten",
  203.               "Nigel Wetten",
  204.               "May 2000",
  205.               N_("<Image>/Filters/Distorts/Wind..."),
  206.               "RGB*",
  207.               GIMP_PLUGIN,
  208.               nargs, 0,
  209.               args, NULL);
  210. }
  211.  
  212. static void
  213. run (gchar   *name,
  214.      gint     nparams,
  215.      GimpParam  *param,
  216.      gint    *nreturn_vals,
  217.      GimpParam **return_vals)
  218. {
  219.   static GimpParam values[1];
  220.   GimpDrawable *drawable;
  221.   GimpRunModeType run_mode;
  222.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  223.  
  224.   run_mode = param[0].data.d_int32;
  225.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  226.   gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
  227.   switch (run_mode)
  228.     {
  229.     case GIMP_RUN_NONINTERACTIVE:
  230.       INIT_I18N();
  231.       if (nparams != 8)
  232.     {
  233.       status = GIMP_PDB_CALLING_ERROR;
  234.     }
  235.       else
  236.     {
  237.       config.threshold = param[3].data.d_int32;
  238.       config.direction = param[4].data.d_int32;
  239.       config.strength = param[5].data.d_int32;
  240.       config.alg = param[6].data.d_int32;
  241.       config.edge = param[7].data.d_int32;
  242.  
  243.       if (render_effect(drawable, 0) == -1)
  244.         status = GIMP_PDB_EXECUTION_ERROR;
  245.     }
  246.       break;
  247.       
  248.     case GIMP_RUN_INTERACTIVE:
  249.       INIT_I18N_UI();
  250.       gimp_get_data("plug_in_wind", &config);
  251.       dialog_box(drawable);
  252.       if (dialog_result == -1)
  253.     {
  254.       status = GIMP_PDB_EXECUTION_ERROR;
  255.       break;
  256.     }
  257.       if (render_effect(drawable, 0) == -1)
  258.     {
  259.       status = GIMP_PDB_CALLING_ERROR;
  260.       break;
  261.     }
  262.       g_free(preview_cache);
  263.       gimp_set_data("plug_in_wind", &config, sizeof(config_t));
  264.       gimp_displays_flush();
  265.       break;
  266.       
  267.     case GIMP_RUN_WITH_LAST_VALS:
  268.       INIT_I18N();
  269.       gimp_get_data("plug_in_wind", &config);
  270.       if (render_effect (drawable, FALSE) == -1)
  271.     {
  272.       status = GIMP_PDB_EXECUTION_ERROR;
  273.       gimp_message("An execution error occured.");
  274.     }
  275.       else
  276.     {
  277.       gimp_displays_flush ();
  278.     }
  279.     }
  280.       
  281.   gimp_drawable_detach(drawable);
  282.   
  283.   *nreturn_vals = 1;
  284.   *return_vals = values;
  285.   values[0].type = GIMP_PDB_STATUS;
  286.   values[0].data.d_status = status;
  287.  
  288.   return;
  289. }
  290.  
  291. static gint
  292. render_effect (GimpDrawable *drawable, 
  293.            gboolean   preview_mode)
  294. {
  295.   if (config.alg == RENDER_WIND)
  296.     {
  297.       render_wind (drawable, config.threshold, config.strength,
  298.            config.direction, config.edge, preview_mode);
  299.     }
  300.   else if (config.alg == RENDER_BLAST)
  301.     {
  302.       render_blast (drawable, config.threshold, config.strength,
  303.             config.direction, config.edge, preview_mode);
  304.     }
  305.   return 0;
  306. }
  307.  
  308. static void
  309. preview_do_row(gint    row,
  310.            gint    width,
  311.            guchar *even,
  312.            guchar *odd,
  313.            guchar *src)
  314. {
  315.   gint    x;
  316.   
  317.   guchar *p0 = even;
  318.   guchar *p1 = odd;
  319.   
  320.   gdouble    r, g, b, a;
  321.   gdouble    c0, c1;
  322.   
  323.   for (x = 0; x < width; x++) 
  324.     {
  325.       if (preview_cache_bpp == 4)
  326.     {
  327.       r = ((gdouble)src[x*4+0]) / 255.0;
  328.       g = ((gdouble)src[x*4+1]) / 255.0;
  329.       b = ((gdouble)src[x*4+2]) / 255.0;
  330.       a = ((gdouble)src[x*4+3]) / 255.0;
  331.     }
  332.       else if (preview_cache_bpp == 3)
  333.     {
  334.       r = ((gdouble)src[x*3+0]) / 255.0;
  335.       g = ((gdouble)src[x*3+1]) / 255.0;
  336.       b = ((gdouble)src[x*3+2]) / 255.0;
  337.       a = 1.0;
  338.     }
  339.       else
  340.     {
  341.       r = ((gdouble)src[x*preview_cache_bpp+0]) / 255.0;
  342.       g = b = r;
  343.       if (preview_cache_bpp == 2)
  344.             a = ((gdouble)src[x*preview_cache_bpp+1]) / 255.0;
  345.       else
  346.         a = 1.0;
  347.     }
  348.       
  349.       if ((x / GIMP_CHECK_SIZE) & 1) 
  350.     {
  351.       c0 = GIMP_CHECK_LIGHT;
  352.       c1 = GIMP_CHECK_DARK;
  353.     } 
  354.       else 
  355.     {
  356.       c0 = GIMP_CHECK_DARK;
  357.       c1 = GIMP_CHECK_LIGHT;
  358.     }
  359.       
  360.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  361.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  362.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  363.       
  364.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  365.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  366.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  367.       
  368.     } /* for */
  369.   
  370.   if ((row / GIMP_CHECK_SIZE) & 1)
  371.     {
  372.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)odd,  0, row, width); 
  373.     }
  374.   else
  375.     {
  376.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)even, 0, row, width); 
  377.     }
  378. }
  379.  
  380. static void
  381. render_blast (GimpDrawable   *drawable,
  382.           gint         threshold,
  383.           gint         strength,
  384.           direction_t  direction,
  385.           edge_t       edge,
  386.           gboolean     preview_mode)
  387. {
  388.   gint x1, x2, y1, y2;
  389.   gint width;
  390.   gint height;
  391.   gint bytes = drawable->bpp;
  392.   guchar *buffer;
  393.   GimpPixelRgn src_region, dest_region;
  394.   gint row;
  395.   gint row_stride;
  396.   gint marker = 0;
  397.   gint lpi;
  398.   guchar *odd = NULL;
  399.   guchar *even = NULL;
  400.  
  401.   if (preview_mode) 
  402.     {
  403.       width  = GTK_PREVIEW (preview)->buffer_width;
  404.       height = GTK_PREVIEW (preview)->buffer_height;
  405.       bytes  = preview_cache_bpp;
  406.  
  407.       x1 = y1 = 0;
  408.       x2 = width;
  409.       y2 = height;
  410.  
  411.       row_stride = preview_cache_rowstride;
  412.       even = g_malloc (width * 3);
  413.       odd  = g_malloc (width * 3);
  414.     } 
  415.   else 
  416.     {
  417.       gimp_progress_init( _("Rendering Blast..."));
  418.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  419.  
  420.       width = x2 - x1;
  421.       height = y2 - y1;
  422.  
  423.       gimp_pixel_rgn_init (&src_region,  drawable, x1, y1, width, height, FALSE, FALSE);
  424.       gimp_pixel_rgn_init (&dest_region, drawable, x1, y1, width, height, TRUE, TRUE);
  425.  
  426.       row_stride = width * bytes;
  427.   }
  428.  
  429.   lpi = row_stride - bytes;
  430.  
  431.   buffer = (guchar *) g_malloc (row_stride);
  432.   
  433.   for (row = y1; row < y2; row++)
  434.     {
  435.       if (preview_mode)
  436.         memcpy (buffer, preview_cache + (row * row_stride), row_stride);
  437.       else
  438.         gimp_pixel_rgn_get_row (&src_region, buffer, x1, row, width);
  439.  
  440.       if (direction == RIGHT)
  441.     {
  442.       reverse_buffer (buffer, row_stride, bytes);
  443.     }
  444.  
  445.       marker = render_blast_row (buffer, bytes, lpi, threshold, strength, edge);
  446.  
  447.       if (direction == RIGHT)
  448.     {
  449.       reverse_buffer (buffer, row_stride, bytes);
  450.     }
  451.  
  452.       if (preview_mode) 
  453.     {
  454.       preview_do_row(row,width,even,odd,buffer);
  455.     } 
  456.       else 
  457.     {
  458.       gimp_pixel_rgn_set_row (&dest_region, buffer, x1, row, width);
  459.       gimp_progress_update ((double) (row - y1)/ (double) (height));
  460.     }
  461.  
  462.       if (marker)
  463.     {
  464.       gint j, limit;
  465.       
  466. #ifdef G_OS_WIN32
  467.       limit = 1 + RAND_FUNC () % 2;
  468. #else
  469.       limit = 1 + rand () % 2;
  470. #endif
  471.       for (j = 0; (j < limit) && (row < y2); j++)
  472.         {
  473.           row++;
  474.           if (row < y2)
  475.         {
  476.                   if (preview_mode) 
  477.             {
  478.               memcpy (buffer, preview_cache + (row * row_stride), row_stride);
  479.               preview_do_row(row,width,even,odd,buffer);
  480.             } 
  481.           else 
  482.             {
  483.               gimp_pixel_rgn_get_row (&src_region, buffer, x1, row, width);
  484.               gimp_pixel_rgn_set_row (&dest_region, buffer, x1, row, width);
  485.             }
  486.         }
  487.         }
  488.       marker = 0;
  489.     }
  490.     }
  491.  
  492.  if(even)
  493.     g_free(even);
  494.  
  495.   if(odd)
  496.     g_free(odd);
  497.  
  498.   g_free(buffer);
  499.   
  500.   /*  update the region  */
  501.   if (preview_mode) 
  502.     {
  503.       gtk_widget_queue_draw (preview);
  504.     }
  505.   else 
  506.     {
  507.       gimp_drawable_flush (drawable);
  508.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  509.       gimp_drawable_update (drawable->id, x1, y1, x2 - x1, y2 - y1);
  510.     }
  511.  
  512.   return;
  513. }
  514.  
  515. static void
  516. render_wind (GimpDrawable   *drawable,
  517.          gint         threshold,
  518.          gint         strength,
  519.          direction_t  direction,
  520.          edge_t       edge,
  521.          gboolean     preview_mode)
  522. {
  523.   GimpPixelRgn src_region, dest_region;
  524.   gint width;
  525.   gint height;
  526.   gint bytes;
  527.   gint row_stride;
  528.   gint comp_stride;
  529.   gint row;
  530.   guchar *sb;
  531.   gint lpi;
  532.   gint x1, y1, x2, y2;
  533.   guchar *odd = NULL;
  534.   guchar *even = NULL;
  535.  
  536.   if (preview_mode) 
  537.     {
  538.       width  = GTK_PREVIEW (preview)->buffer_width;
  539.       height = GTK_PREVIEW (preview)->buffer_height;
  540.       bytes  = preview_cache_bpp;
  541.  
  542.       x1 = y1 = 0;
  543.       x2 = width;
  544.       y2 = height;
  545.  
  546.       row_stride = preview_cache_rowstride;
  547.       even = g_malloc (width * 3);
  548.       odd  = g_malloc (width * 3);
  549.     } 
  550.   else 
  551.     {
  552.       gimp_progress_init( _("Rendering Wind..."));
  553.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  554.  
  555.       bytes = drawable->bpp;
  556.       width = x2 - x1;
  557.       height = y2 - y1;
  558.  
  559.       gimp_pixel_rgn_init (&src_region, drawable, x1, y1, width, height, FALSE, FALSE);
  560.       gimp_pixel_rgn_init (&dest_region, drawable, x1, y1, width, height, TRUE, TRUE);
  561.  
  562.       row_stride = width * bytes;
  563.     }
  564.   
  565.   comp_stride = bytes * COMPARE_WIDTH;
  566.   lpi = row_stride - comp_stride;
  567.  
  568.   sb = g_malloc (row_stride);
  569.   
  570.   for (row = y1; row < y2; row++)
  571.     {
  572.       if (preview_mode) 
  573.     memcpy (sb, preview_cache + (row * row_stride), row_stride);
  574.       else 
  575.     gimp_pixel_rgn_get_row (&src_region, sb, x1, row, width);
  576.  
  577.       if (direction == RIGHT)
  578.     reverse_buffer (sb, row_stride, bytes);
  579.       
  580.       render_wind_row (sb, bytes, lpi, threshold, strength, edge);
  581.  
  582.       if (direction == RIGHT)
  583.     reverse_buffer(sb, row_stride, bytes);
  584.  
  585.       if (preview_mode) 
  586.     {
  587.       preview_do_row(row,width,even,odd,sb);
  588.     } 
  589.       else 
  590.     {
  591.       gimp_pixel_rgn_set_row (&dest_region, sb, x1, row, width);
  592.       gimp_progress_update ((double) (row - y1)/ (double) (height));
  593.     }
  594.     }
  595.  
  596.   if(even)
  597.     g_free(even);
  598.  
  599.   if(odd)
  600.     g_free(odd);
  601.  
  602.   g_free(sb);
  603.  
  604.   /*  update the region  */
  605.   if (preview_mode) 
  606.     {
  607.       gtk_widget_queue_draw (preview);
  608.     } 
  609.   else 
  610.     {
  611.       gimp_drawable_flush (drawable);
  612.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  613.       gimp_drawable_update (drawable->id, x1, y1, x2 - x1, y2 - y1);
  614.     }
  615.  
  616.   return;
  617. }
  618.  
  619. static gint
  620. render_blast_row (guchar *buffer,
  621.           gint    bytes,
  622.           gint    lpi,
  623.           gint    threshold,
  624.           gint    strength,
  625.           edge_t  edge)
  626. {
  627.   gint Ri, Gi, Bi, Ai= 0;
  628.   gint sbi, lbi;
  629.   gint bleed_length;
  630.   gint i, j;
  631.   gint weight, random_factor;
  632.   gint skip = 0;
  633.  
  634.   for (j = 0; j < lpi; j += bytes)
  635.     {
  636.       Ri = j; Gi = j + 1; Bi = j + 2;
  637.  
  638.       if(bytes > 3)
  639.     Ai = j + 3;
  640.       
  641.       if (threshold_exceeded(buffer+Ri, buffer+Ri+bytes, edge, threshold, (bytes > 3)))
  642.     {
  643.       /* we have found an edge, do bleeding */
  644.       sbi = Ri;
  645.           
  646. #ifdef G_OS_WIN32
  647.       weight = RAND_FUNC () % 10;
  648. #else
  649.       weight = rand() % 10;
  650. #endif
  651.       if (weight > 5)
  652.         {
  653.           random_factor = 2;
  654.         }
  655.       else if (weight > 3)
  656.         {
  657.           random_factor = 3;
  658.         }
  659.       else
  660.         {
  661.           random_factor = 4;
  662.         }
  663.       bleed_length = 0;
  664. #ifdef G_OS_WIN32
  665.       switch (RAND_FUNC () % random_factor)
  666. #else
  667.       switch (rand() % random_factor)
  668. #endif
  669.         {
  670.         case 3:
  671.           bleed_length += strength;
  672.           /* fall through to add up multiples of strength */
  673.         case 2:
  674.           bleed_length += strength;
  675.           /* fall through */
  676.         case 1:
  677.           bleed_length += strength;
  678.           /* fall through */
  679.         case 0:
  680.           bleed_length += strength;
  681.           /* fall through */
  682.         }
  683.  
  684.       lbi = sbi + bytes * bleed_length;
  685.       if (lbi > lpi)
  686.         {
  687.           lbi = lpi;
  688.         }
  689.  
  690.       for (i = sbi; i < lbi; i += bytes)
  691.         {
  692.           buffer[i] = buffer[Ri];
  693.           buffer[i+1] = buffer[Gi];
  694.           buffer[i+2] = buffer[Bi];
  695.           if(bytes > 3)
  696.         buffer[i+3] = buffer[Ai];
  697.         }
  698.       j = lbi - bytes;
  699. #ifdef G_OS_WIN32
  700.       if ((RAND_FUNC () % 10) > 7)
  701. #else
  702.       if ((rand() % 10) > 7)
  703. #endif
  704.         {
  705.           skip = 1;
  706.         }
  707.     }
  708.     }
  709.   return skip;
  710. }
  711.  
  712. static void
  713. render_wind_row (guchar *sb,
  714.          gint    bytes,
  715.          gint    lpi,
  716.          gint    threshold,
  717.          gint    strength,
  718.          edge_t  edge)
  719. {
  720.   gint i, j;
  721.   gint bleed_length;
  722.   gint blend_amt_R, blend_amt_G, blend_amt_B, blend_amt_A = 0 ;
  723.   gint blend_colour_R, blend_colour_G, blend_colour_B, blend_colour_A = 0 ;
  724.   gint target_colour_R, target_colour_G, target_colour_B, target_colour_A = 0;
  725.   gdouble bleed_length_max;
  726.   gint bleed_variation;
  727.   gint n;
  728.   gint sbi;  /* starting bleed index */
  729.   gint lbi;     /* last bleed index */
  730.   gdouble denominator;
  731.   gint comp_stride = bytes * COMPARE_WIDTH;
  732.   
  733.   for (j = 0; j < lpi; j += bytes)
  734.     {
  735.       gint Ri = j;
  736.       gint Gi = j + 1;
  737.       gint Bi = j + 2;
  738.       gint Ai = 0;
  739.  
  740.       if(bytes > 3)
  741.     Ai = j + 3;
  742.  
  743.       if (threshold_exceeded(sb+Ri, sb+Ri+comp_stride, edge, threshold,(bytes > 3)))
  744.     {
  745.       /* we have found an edge, do bleeding */
  746.       sbi = Ri + comp_stride;
  747.       blend_colour_R = sb[Ri];
  748.       blend_colour_G = sb[Gi];
  749.       blend_colour_B = sb[Bi];
  750.       target_colour_R = sb[sbi];
  751.       target_colour_G = sb[sbi+1];
  752.       target_colour_B = sb[sbi+2];
  753.       bleed_length_max = strength;
  754.  
  755.       if(bytes > 3)
  756.         {
  757.           blend_colour_A = sb[Ai];
  758.           target_colour_A = sb[sbi+3];
  759.         }
  760.  
  761. #ifdef G_OS_WIN32
  762.       if (RAND_FUNC () % 3) /* introduce weighted randomness */
  763. #else
  764.       if (rand() % 3) /* introduce weighted randomness */
  765. #endif
  766.         {
  767.           bleed_length_max = strength;
  768.         }
  769.       else
  770.         {
  771.           bleed_length_max = 4 * strength;
  772.         }
  773.  
  774.       bleed_variation = 1
  775. #ifdef G_OS_WIN32
  776.         + (gint) (bleed_length_max * RAND_FUNC () / (G_MAXRAND + 1.0));
  777. #else
  778.         + (gint) (bleed_length_max * rand() / (G_MAXRAND + 1.0));
  779. #endif
  780.  
  781.       lbi = sbi + bleed_variation * bytes;
  782.       if (lbi > lpi)
  783.         {
  784.           lbi = lpi; /* stop overunning the buffer */
  785.         }
  786.  
  787.       bleed_length = bleed_variation;
  788.  
  789.       blend_amt_R = target_colour_R - blend_colour_R;
  790.       blend_amt_G = target_colour_G - blend_colour_G;
  791.       blend_amt_B = target_colour_B - blend_colour_B;
  792.       if(bytes > 3)
  793.         {
  794.            blend_amt_A = target_colour_A - blend_colour_A;
  795.         }
  796.       denominator = bleed_length * bleed_length + bleed_length;
  797.       denominator = 2.0 / denominator;
  798.       n = bleed_length;
  799.       for (i = sbi; i < lbi; i += bytes)
  800.         {
  801.  
  802.           /* check against original colour */
  803.           if (!threshold_exceeded(sb+Ri, sb+i, edge, threshold,(bytes>3))
  804. #ifdef G_OS_WIN32
  805.           && (RAND_FUNC () % 2))
  806. #else
  807.           && (rand() % 2))
  808. #endif
  809.         {
  810.           break;
  811.         }
  812.  
  813.           blend_colour_R += blend_amt_R * n * denominator;
  814.           blend_colour_G += blend_amt_G * n * denominator;
  815.           blend_colour_B += blend_amt_B * n * denominator;
  816.  
  817.           if(bytes > 3)
  818.         {
  819.           blend_colour_A += blend_amt_A * n * denominator;
  820.           if (blend_colour_A > 255) blend_colour_A = 255;
  821.           else if (blend_colour_A < 0) blend_colour_A = 0;
  822.         }
  823.  
  824.           if (blend_colour_R > 255) blend_colour_R = 255;
  825.           else if (blend_colour_R < 0) blend_colour_R = 0;
  826.           if (blend_colour_G > 255) blend_colour_G = 255;
  827.           else if (blend_colour_G < 0) blend_colour_G = 0;
  828.           if (blend_colour_B > 255) blend_colour_B = 255;
  829.           else if (blend_colour_B < 0) blend_colour_B = 0;
  830.  
  831.           sb[i] = (blend_colour_R * 2 + sb[i]) / 3;
  832.           sb[i+1] = (blend_colour_G * 2 + sb[i+1]) / 3;
  833.           sb[i+2] = (blend_colour_B * 2 + sb[i+2]) / 3;
  834.  
  835.           if(bytes > 3)
  836.         sb[i+3] = (blend_colour_A * 2 + sb[i+3]) / 3;
  837.  
  838.           if (threshold_exceeded(sb+i, sb+i+comp_stride, BOTH,
  839.                      threshold,(bytes>3)))
  840.         {
  841.           target_colour_R = sb[i+comp_stride];
  842.           target_colour_G = sb[i+comp_stride+1];
  843.           target_colour_B = sb[i+comp_stride+2];
  844.           if(bytes > 3)
  845.             target_colour_A = sb[i+comp_stride+3];
  846.           blend_amt_R = target_colour_R - blend_colour_R;
  847.           blend_amt_G = target_colour_G - blend_colour_G;
  848.           blend_amt_B = target_colour_B - blend_colour_B;
  849.           if(bytes > 3)
  850.             blend_amt_A = target_colour_A - blend_colour_A;
  851.           denominator = n * n + n;
  852.           denominator = 2.0 / denominator;
  853.         }
  854.           n--;
  855.         }
  856.     }
  857.     }
  858.   return;
  859. }
  860.  
  861. static gint
  862. threshold_exceeded (guchar  *pixel_R1,
  863.             guchar  *pixel_R2,
  864.             edge_t   edge,
  865.             gint     threshold,
  866.             gboolean has_alpha)
  867. {
  868.   gint derivative_R, derivative_G, derivative_B, derivative_A;
  869.   gint return_value;
  870.  
  871.   get_derivative(pixel_R1, pixel_R2, edge, has_alpha,
  872.          &derivative_R, &derivative_G, &derivative_B, &derivative_A);
  873.  
  874.   if(((derivative_R + 
  875.        derivative_G + 
  876.        derivative_B + 
  877.        derivative_A) / 4) > threshold)
  878.     {
  879.       return_value = 1;
  880.     }
  881.   else
  882.     {
  883.       return_value = 0;
  884.     }
  885.   return return_value;
  886. }
  887.  
  888. static void
  889. get_derivative (guchar  *pixel_R1,
  890.         guchar  *pixel_R2,
  891.         edge_t   edge,
  892.         gboolean has_alpha,
  893.         gint    *derivative_R,
  894.         gint    *derivative_G,
  895.         gint    *derivative_B,
  896.         gint    *derivative_A)
  897. {
  898.   guchar *pixel_G1 = pixel_R1 + 1;
  899.   guchar *pixel_B1 = pixel_R1 + 2;
  900.   guchar *pixel_G2 = pixel_R2 + 1;
  901.   guchar *pixel_B2 = pixel_R2 + 2;
  902.   guchar *pixel_A1;
  903.   guchar *pixel_A2;
  904.  
  905.   if(has_alpha)
  906.     {
  907.       pixel_A1 = pixel_R1 + 3;
  908.       pixel_A2 = pixel_R2 + 3;
  909.       *derivative_A = *pixel_A2 - *pixel_A1;
  910.     }
  911.   else
  912.     {
  913.       *derivative_A = 0;
  914.     }
  915.  
  916.   *derivative_R = *pixel_R2 - *pixel_R1;
  917.   *derivative_G = *pixel_G2 - *pixel_G1;
  918.   *derivative_B = *pixel_B2 - *pixel_B1;
  919.   
  920.   if (edge == BOTH)
  921.     {
  922.       *derivative_R = abs(*derivative_R);
  923.       *derivative_G = abs(*derivative_G);
  924.       *derivative_B = abs(*derivative_B);
  925.       *derivative_A = abs(*derivative_A);
  926.     }
  927.   else if (edge == LEADING)
  928.     {
  929.       *derivative_R = -(*derivative_R);
  930.       *derivative_G = -(*derivative_G);
  931.       *derivative_B = -(*derivative_B);
  932.       *derivative_A = -(*derivative_A);
  933.     }
  934.   else if (edge == TRAILING)
  935.     {
  936.       /* no change needed */
  937.     }
  938.   return;
  939. }
  940.  
  941. static void
  942. reverse_buffer (guchar *buffer,
  943.         gint    length,
  944.         gint    bytes)
  945. {
  946.   gint i, si;
  947.   gint temp;
  948.   gint midpoint;
  949.   
  950.   midpoint = length / 2;
  951.   for (i = 0; i < midpoint; i += bytes)
  952.     {
  953.       si = length - bytes - i;
  954.       
  955.       temp = buffer[i];
  956.       buffer[i] = buffer[si];
  957.       buffer[si] = (guchar) temp;
  958.  
  959.       temp = buffer[i+1];
  960.       buffer[i+1] = buffer[si+1];
  961.       buffer[si+1] = (guchar) temp;
  962.  
  963.       temp = buffer[i+2];
  964.       buffer[i+2] = buffer[si+2];
  965.       buffer[si+2] = (guchar) temp;
  966.  
  967.       if(bytes > 3)
  968.     {
  969.       temp = buffer[i+3];
  970.       buffer[i+3] = buffer[si+3];
  971.       buffer[si+3] = (guchar) temp;
  972.     }
  973.     }
  974.  
  975.   return;
  976. }
  977.  
  978. /***************************************************
  979.   GUI 
  980.  ***************************************************/
  981.  
  982. static void
  983. ok_callback (GtkWidget *widget,
  984.          gpointer   data)
  985. {
  986.   /* we have to stop the dialog from being closed with strength < 1 */
  987.   /* since we use spinbuttons this should never happen ...          */
  988.   if (config.strength < 1)
  989.     {
  990.       g_message (_("Wind Strength must be greater than 0."));
  991.     }
  992.   else
  993.     {
  994.       dialog_result = 1;
  995.       gtk_widget_destroy (GTK_WIDGET (data));
  996.     }
  997. }
  998.  
  999. static void
  1000. radio_callback (GtkWidget *widget, 
  1001.         gpointer   data)
  1002. {
  1003.   GimpDrawable *drawable;
  1004.  
  1005.   gimp_radio_button_update (widget, data);
  1006.  
  1007.   if (GTK_TOGGLE_BUTTON (widget)->active)
  1008.     {
  1009.       drawable = gtk_object_get_data (GTK_OBJECT (widget), "drawable");
  1010.       if (drawable != NULL)
  1011.     render_effect (drawable, TRUE);
  1012.     }
  1013. }
  1014.  
  1015. static void
  1016. dialog_box (GimpDrawable *drawable)
  1017. {
  1018.   GtkWidget *main_vbox;
  1019.   GtkWidget *vbox;
  1020.   GtkWidget *abox;
  1021.   GtkWidget *table;
  1022.   GtkObject *adj;
  1023.   GtkWidget *frame;
  1024.   GtkWidget *dlg;
  1025.   GtkWidget *style1;
  1026.   GtkWidget *style2;
  1027.   GtkWidget *dir1;
  1028.   GtkWidget *dir2;
  1029.   GtkWidget *edge1;
  1030.   GtkWidget *edge2;
  1031.   GtkWidget *edge3;
  1032.  
  1033.   gimp_ui_init ("wind", TRUE);
  1034.  
  1035.   dlg = gimp_dialog_new ( _("Wind"), "wind",
  1036.              gimp_standard_help_func, "filters/wind.html",
  1037.              GTK_WIN_POS_MOUSE,
  1038.              FALSE, TRUE, FALSE,
  1039.  
  1040.              _("OK"), ok_callback,
  1041.              NULL, NULL, NULL, TRUE, FALSE,
  1042.              _("Cancel"), gtk_widget_destroy,
  1043.              NULL, 1, NULL, FALSE, TRUE,
  1044.  
  1045.              NULL);
  1046.  
  1047.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  1048.               GTK_SIGNAL_FUNC (gtk_main_quit),
  1049.               NULL);
  1050.  
  1051.   /* init tooltips */
  1052.   gimp_help_init ();
  1053.   
  1054.   vbox = gtk_vbox_new (FALSE, 2);
  1055.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
  1056.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0);
  1057.   gtk_widget_show (vbox);
  1058.  
  1059.   frame = gtk_frame_new (_("Preview"));
  1060.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1061.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  1062.   gtk_widget_show (frame);
  1063.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1064.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  1065.   gtk_container_add (GTK_CONTAINER (frame), abox);
  1066.   gtk_widget_show (abox);
  1067.   frame = gtk_frame_new (NULL);
  1068.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1069.   gtk_container_add (GTK_CONTAINER (abox), frame);
  1070.   gtk_widget_show (frame);
  1071.   preview = preview_widget (drawable); /* we are here */
  1072.   gtk_container_add (GTK_CONTAINER (frame), preview);
  1073.   render_effect (drawable, TRUE); /* render preview image */
  1074.   gtk_widget_show (preview);
  1075.  
  1076.   frame = gtk_frame_new (_("Parameter Settings"));
  1077.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1078.   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  1079.   gtk_widget_show (frame);
  1080.  
  1081.   main_vbox = gtk_vbox_new (FALSE, 4);
  1082.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  1083.   gtk_container_add (GTK_CONTAINER (frame), main_vbox);
  1084.   gtk_widget_show (main_vbox);
  1085.  
  1086.   /*****************************************************
  1087.     outer frame and table
  1088.   ***************************************************/
  1089.  
  1090.   table = gtk_table_new (1, 3, FALSE);
  1091.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1092.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1093.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  1094.  
  1095.   /*********************************************************
  1096.     radio buttons for choosing wind rendering algorithm
  1097.     ******************************************************/
  1098.  
  1099.   frame = gimp_radio_group_new2 (TRUE, _("Style"),
  1100.                  radio_callback,
  1101.                  &config.alg, (gpointer) config.alg,
  1102.                  _("Wind"),  (gpointer) RENDER_WIND,  &style1,
  1103.                  _("Blast"), (gpointer) RENDER_BLAST, &style2,
  1104.  
  1105.                  NULL);
  1106.   gtk_object_set_data (GTK_OBJECT (style1), "drawable", drawable);
  1107.   gtk_object_set_data (GTK_OBJECT (style2), "drawable", drawable);
  1108.  
  1109.   gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
  1110.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1111.   gtk_widget_show (frame);
  1112.  
  1113.   /******************************************************
  1114.     radio buttons for choosing LEFT or RIGHT
  1115.     **************************************************/
  1116.  
  1117.   frame = gimp_radio_group_new2 (TRUE, _("Direction"),
  1118.                  radio_callback,
  1119.                  &config.direction, (gpointer) config.direction,
  1120.                  _("Left"),  (gpointer) LEFT,  &dir1,
  1121.                  _("Right"), (gpointer) RIGHT, &dir2,
  1122.                  NULL);
  1123.   gtk_object_set_data (GTK_OBJECT (dir1), "drawable", drawable);
  1124.   gtk_object_set_data (GTK_OBJECT (dir2), "drawable", drawable);
  1125.  
  1126.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
  1127.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1128.   gtk_widget_show (frame);
  1129.   
  1130.   /*****************************************************
  1131.     radio buttons for choosing BOTH, LEADING, TRAILING
  1132.     ***************************************************/
  1133.  
  1134.   frame = gimp_radio_group_new2 (TRUE, _("Edge Affected"),
  1135.                  radio_callback,
  1136.                  &config.edge, (gpointer) config.edge,
  1137.  
  1138.                  _("Leading"),  (gpointer) LEADING,  &edge1,
  1139.                  _("Trailing"), (gpointer) TRAILING, &edge2,
  1140.                  _("Both"),     (gpointer) BOTH,     &edge3,
  1141.  
  1142.                  NULL);
  1143.   gtk_object_set_data (GTK_OBJECT (edge1), "drawable", drawable);
  1144.   gtk_object_set_data (GTK_OBJECT (edge2), "drawable", drawable);
  1145.   gtk_object_set_data (GTK_OBJECT (edge3), "drawable", drawable);
  1146.  
  1147.   gtk_table_attach (GTK_TABLE (table), frame, 2, 3, 0, 1,
  1148.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1149.   gtk_widget_show (frame);
  1150.  
  1151.   gtk_widget_show (table);
  1152.  
  1153.   /****************************************************
  1154.    table for sliders
  1155.    ****************************************************/
  1156.   table = gtk_table_new (2, 3, FALSE);
  1157.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1158.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1159.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  1160.  
  1161.   /*****************************************************
  1162.     slider and entry for threshold
  1163.     ***************************************************/
  1164.  
  1165.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  1166.                   _("Threshold:"), SCALE_WIDTH, 0,
  1167.                   config.threshold,
  1168.                   MIN_THRESHOLD, MAX_THRESHOLD, 1.0, 10, 0,
  1169.                   TRUE, 0, 0,
  1170.                   _("Higher values restrict the effect to fewer areas of the image"), NULL);
  1171.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1172.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1173.               &config.threshold);
  1174.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  1175.                  GTK_SIGNAL_FUNC (render_effect),
  1176.                  (gpointer)drawable);
  1177.  
  1178.   /*****************************************************
  1179.     slider and entry for strength of wind
  1180.     ****************************************************/
  1181.  
  1182.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  1183.                   _("Strength:"), SCALE_WIDTH, 0,
  1184.                   config.strength,
  1185.                   MIN_STRENGTH, MAX_STRENGTH, 1.0, 10.0, 0,
  1186.                   TRUE, 0, 0,
  1187.                   _("Higher values increase the magnitude of the effect"), NULL);
  1188.  
  1189.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1190.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1191.               &config.strength);
  1192.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  1193.                  GTK_SIGNAL_FUNC (render_effect),
  1194.                  (gpointer)drawable);
  1195.  
  1196.   gtk_widget_show (table);
  1197.  
  1198.   gtk_widget_show (dlg);
  1199.  
  1200.   gtk_main ();
  1201.   gdk_flush ();
  1202. }
  1203.  
  1204.  
  1205. static GtkWidget *
  1206. preview_widget (GimpDrawable *drawable)
  1207. {
  1208.   gint       size;
  1209.  
  1210.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  1211.   fill_preview (preview, drawable);
  1212.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  1213.  
  1214.   return preview;
  1215. }
  1216.  
  1217. static void
  1218. fill_preview (GtkWidget *widget, 
  1219.           GimpDrawable *drawable)
  1220. {
  1221.   GimpPixelRgn  srcPR;
  1222.   gint       width;
  1223.   gint       height;
  1224.   gint       x1, x2, y1, y2;
  1225.   gint       bpp;
  1226.   gint       y;
  1227.   guchar    *src;
  1228.   guchar    *even, *odd;
  1229.   
  1230.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  1231.  
  1232.   if (x2 - x1 > PREVIEW_SIZE)
  1233.     x2 = x1 + PREVIEW_SIZE;
  1234.   
  1235.   if (y2 - y1 > PREVIEW_SIZE)
  1236.     y2 = y1 + PREVIEW_SIZE;
  1237.   
  1238.   width  = x2 - x1;
  1239.   height = y2 - y1;
  1240.   bpp    = gimp_drawable_bpp (drawable->id);
  1241.   
  1242.   if (width < 1 || height < 1)
  1243.     return;
  1244.  
  1245.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  1246.  
  1247.   gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, x2, y2, FALSE, FALSE);
  1248.  
  1249.   even = g_malloc (width * 3);
  1250.   odd  = g_malloc (width * 3);
  1251.   src  = g_malloc (width * bpp);
  1252.   preview_cache = g_malloc(width * bpp * height);
  1253.   preview_cache_rowstride = width * bpp;
  1254.   preview_cache_bpp = bpp;
  1255.  
  1256.   for (y = 0; y < height; y++)
  1257.     {
  1258.       gimp_pixel_rgn_get_row (&srcPR, src, x1, y + y1, width);
  1259.       memcpy(preview_cache + (y*width*bpp),src,width*bpp);
  1260.     }
  1261.   
  1262.   for (y = 0; y < height; y++)
  1263.     {
  1264.       preview_do_row(y,width,even,odd,preview_cache + (y*width*bpp));
  1265.     }
  1266.  
  1267.  
  1268.   g_free (even);
  1269.   g_free (odd);
  1270.   g_free (src);
  1271. }
  1272.